package rps.client.ui;

import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Insets;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.rmi.RemoteException;
import java.util.ArrayList;

import javax.swing.BoxLayout;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JTextPane;
import javax.swing.SwingConstants;

import rps.client.GameController;
import rps.client.UIController;
import rps.game.Game;
import rps.game.data.Figure;
import rps.game.data.FigureKind;
import rps.game.data.Player;

public class GamePane {
	private final JPanel gamePane = new JPanel();
	
	private final JPanel controlPanel = new JPanel();
	
	private final JLabel statusPanel = new JLabel();
	private final JPanel chatPanel = new JPanel();
	private final JTextField chatInput = new JTextField();
	private final JTextPane chat = new JTextPane();
	private final JScrollPane scrollPane = new JScrollPane(chat);
	
	private String chatString = new String();
	private String lastChatMessage = new String();
	
	private BoardPanel boardPanel = new BoardPanel(this);
	
	private final WeaponChoicePanel weaponChoicePanel = new WeaponChoicePanel(this);
	
	private final InitialAssignmentPanel initialAssignmentPanel = new InitialAssignmentPanel(this);

	private Game game;
	
	public UIController uiController;
	public GameController gameController;

	public GamePane(Container parent, UIController uiController, GameController gameController) {
		
		this.uiController = uiController;
		this.gameController = gameController;

		gamePane.setLayout(null);
				
		Font dotFont = MediaProvider.getMediaProvider().getFont("dotFont");
		if(dotFont!=null) statusPanel.setFont(dotFont);
		statusPanel.setForeground(Color.blue);
		statusPanel.setHorizontalAlignment(SwingConstants.CENTER);
		
		chatPanel.setLayout(new BoxLayout(chatPanel, BoxLayout.Y_AXIS));
		
		chat.setEditable(false);
		chat.setContentType("text/html");
		chatPanel.add(scrollPane);
		
		chatInput.setMaximumSize(new Dimension(300,20));
		chatPanel.add(chatInput);

		controlPanel.setLayout(new BoxLayout(controlPanel, BoxLayout.Y_AXIS));
		controlPanel.add(weaponChoicePanel);
		controlPanel.add(initialAssignmentPanel);
		controlPanel.add(chatPanel);
		controlPanel.setMaximumSize(UIController.CONTROL_DIMENSION);
		
		Insets frameInset = parent.getInsets();
		//StatusPanel:		x=1000		y=40
		gamePane.add(statusPanel);
		statusPanel.setBounds(frameInset.left, frameInset.top, 1000, 40);
		
		//BoardPanel:		x=700		y=600
		gamePane.add(boardPanel);
		boardPanel.setBounds(frameInset.left, frameInset.top+40, 700, 600);
		
		//controlPanel:		x=300		y=600
		gamePane.add(controlPanel);
		controlPanel.setBounds(frameInset.left+700, frameInset.top+40, 300, 600);		

		gamePane.setVisible(false);

		parent.add(gamePane);
		parent.setPreferredSize(new Dimension(1000, 640));

		bindButtons();
	}
	
	/**
	 * Add Keylistener to Chatline
	 */
	private void bindButtons() {
		chatInput.addKeyListener(new KeyListener() {
			@Override
			public void keyPressed(KeyEvent e) {
				boolean isEnter = e.getKeyCode() == KeyEvent.VK_ENTER;
				if (isEnter) {
					addToChat();
				}
			}
			@Override
			public void keyTyped(KeyEvent e) {}
			@Override
			public void keyReleased(KeyEvent e) {}
		});
	}

	private void addToChat() {
		String message = chatInput.getText().trim();
		if (message.length() > 0) {
			try {
				game.sendMessage(uiController.getPlayer(), message);
				chatInput.setText("");
			} catch (RemoteException e) {
				e.printStackTrace();
			}
		}
	}

	public void hide() {
		gamePane.setVisible(false);
	}

	public void startGame(Game game) {
		reset();
		this.game = game;
		setPlacementPhaseWithEnabling(0);
		gamePane.setVisible(true);
	}
	
	/**
	 * Adds a message to the Chatpanel. If the sender is null, the message is handled as private.
	 * @param sender
	 * @param message
	 */
	public void receivedMessage(Player sender, String message) {
		if (chatString.length() != 0) {
			chatString += "<br>";
		}
		
		if(lastChatMessage.length() != 0){
			chatString += lastChatMessage;
		}
		
		if(sender != null){
			lastChatMessage = "<span style='color:#888888; font-weight:bold;'>[" + sender.getNick() + "]</span> ";
		}
		else{
			lastChatMessage = "<span style='color:#888888; font-weight:bold;'>[Privat]</span> ";
		}

		lastChatMessage += message;
		
		String chatTextToUpdate = "";
		if(chatString.length() == 0){
			chatTextToUpdate = "<html><body><div style='font-family:Arial; font-size:10px;'>"
				+ "<span style='background-color:#FFFF99;'>" + lastChatMessage + "</span>"
				+ "</div></body></html>";
		}
		else{
			chatTextToUpdate = "<html><body><div style='font-family:Arial; font-size:10px;'>"
					+ chatString
					+ "<br>"
					+ "<span style='background-color:#FFFF99;'>" + lastChatMessage + "</span>"
					+ "</div></body></html>";
		}
		
		chat.setText(chatTextToUpdate);
		
		chat.setCaretPosition(chat.getDocument().getLength());
	}

	public void reset() {
		chat.setText(null);
		chatString = "";
		lastChatMessage = "";
		game = null;
		
		boardPanel.reset();
		weaponChoicePanel.reset();
		initialAssignmentPanel.reset();
	}
	
	/**
	 * Updates the Board and the buttons with the given figureset
	 * @param figures
	 */
	public void updateBoard(Figure[] figures){
		boardPanel.updateBoard(figures);
		repaintBoard();

	}
	
	/**
	 * Enables or Disables the initialAssignmentPanel
	 * @param enable
	 */
	public void enableInitialAssignmentPanel(boolean enable){
		initialAssignmentPanel.enable(enable);
	}
	
	/**
	 * Enables or Disables the weaponChoicePanel
	 * @param enable
	 */
	public void enableWeaponChoicePanel(boolean enable){
		weaponChoicePanel.enable(enable);
	}
	/**
	 * {@inheritDoc}
	 */
	public void enableButtons(boolean enable){
		boardPanel.enableButtons(enable);
	}
	
	/**
	 * {@inheritDoc}
	 */
	public void enableSpecialButtons(ArrayList<Integer> list){
		boardPanel.enableSpecialButtons(list);
	}
	
	/**
	 * Sets the Text of the statuspane in the gamepane
	 * @param s
	 */
	public void setStatusText(String s){
		statusPanel.setText(s);
	}
	
	/**
	 * Returns the index all of all Possible Moves in the BoardArray for the given Figure
	 * @param index The index of the figure whose moves are wanted
	 * @return An ArrayList of Integers containing the Index of the possible moved-to-Fields 
	 */
	public ArrayList<Integer> getPossibleMoves(int index, Figure[] field){
		ArrayList<Integer> moves = new ArrayList<Integer>();
		
		if(field[index].getKind().equals(FigureKind.FLAG) ||
			field[index].getKind().equals(FigureKind.TRAP)){
			return moves;
		}
	
		// Move up
		if(getRow(index) > 0)
			if(field[index - 7] == null || !field[index - 7].belongsTo(uiController.getPlayer()))
				moves.add(index - 7);

		// Move right
		if(getCol(index) < 6)
			if(field[index + 1] == null || !field[index + 1].belongsTo(uiController.getPlayer()))
				moves.add(index + 1);
		
		// Move down
		if(getRow(index) < 5)
			if(field[index + 7] == null || !field[index + 7].belongsTo(uiController.getPlayer()))
				moves.add(index + 7);
		
		// Move left
		if(getCol(index) > 0)
			if(field[index - 1] == null || !field[index - 1].belongsTo(uiController.getPlayer()))
				moves.add(index - 1);
		
		return moves;
	}
	private int getRow(int index){
		return index/7;
	}
	
	private int getCol(int index){
		return index%7;
	}
	
	/**
	 * {@inheritDoc}
	 */
	public void repaintBoard(){
		boardPanel.repaintAll();
	}
	
	public FigureKind[] getInitialFigures(){
		FigureKind[] newfigures = new FigureKind[2*BoardPanel.COLS];
		for(int i=0;i<newfigures.length;i++){
			if(boardPanel.getFigures()[i+28] != null)
				newfigures[i] = boardPanel.getFigures()[i+28].getKind();
		}
		return newfigures;
	}
	
	/**
	 * {@inheritDoc}
	 * @param p
	 */
	public void setPlacementPhaseWithEnabling(int p){
		initialAssignmentPanel.setPlacementPhaseWithEnabling(p);
	}
	public void generateRandomAssignment(String s){
		initialAssignmentPanel.generateRandomAssignment(s);
	}
	
	/**
	 * Handles the gamePane relevant aspects of an attacking.
	 * Resets the old LastMove and sets the new one.
	 * Also starts the moveAnimation.
	 * @param fromIndex
	 * @param toIndex
	 * @param newField
	 */
	public void figureMoved(int fromIndex, int toIndex, final Figure[] newField){
		boardPanel.resetLastMove();
		boardPanel.setLastMove(fromIndex, fromIndex-toIndex);
		moveAnimation(fromIndex, toIndex, newField);
	}
	
	/**
	 * Handles the gamePane relevant aspects of an attacking.
	 * Resets the old LastMove and sets the new one.
	 * Starts the moveAnimation
	 * @param fromIndex
	 * @param toIndex
	 * @param attackingFigure Unused. Only passed through by UiControlle-Method
	 * @param defendingFigure Unused. Only passed through by UiControlle-Method
	 * @param newField
	 */
	public void figureAttacked(int fromIndex, int toIndex, Figure attackingFigure, Figure defendingFigure, final Figure[] newField){
		boardPanel.resetLastMove();
		boardPanel.setLastMove(fromIndex, fromIndex-toIndex);
		moveAnimation(fromIndex, toIndex, newField);
	}

	private void moveAnimation(int fromIndex, int toIndex, final Figure[] newField) {		
		
		Animator ani = new Animator(fromIndex, toIndex, MediaProvider.getMediaProvider().buttonImage(boardPanel.getFigures()[fromIndex], uiController.getPlayer(), -1, -1), boardPanel, 200, 100) {
			@Override
			public void callback() {
				updateBoard(newField);
			}
		};
		
		ani.skywalker();
	}
}